package com.giggle.common.helper;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author guozichen
 * @ClassName:
 * @Description: (反射工具类)
 * @date 2020/8/26 14:17
 */
public class ReflectHelper {


    private static Logger logger = LoggerFactory.getLogger(ReflectionUtils.class);

    public ReflectHelper() {
    }

    public static List<Field> getAllFields(Class clz) {
        ArrayList fields = new ArrayList();

        do {
            fields.addAll(Lists.newArrayList(clz.getDeclaredFields()));
            clz = clz.getSuperclass();
        } while(!Object.class.equals(clz));

        return fields;
    }

    public static Field getField(Class clz, String fileName) throws Exception {
        Field field = null;
        Class orgClz = clz;

        do {
            try {
                field = clz.getDeclaredField(fileName);
            } catch (NoSuchFieldException var5) {
            }

            clz = clz.getSuperclass();
        } while(field == null && !Object.class.equals(clz));

        if (field != null) {
            return field;
        } else {
            throw new Exception("查找class:" + orgClz.getName() + "的field:" + fileName + " 失败");
        }
    }

    public static Object invokeGetterMethod(Object obj, String propertyName) {
        String getterMethodName = "get" + StringUtils.capitalize(propertyName);
        return invokeMethod(obj, getterMethodName, new Class[0], new Object[0]);
    }

    public static void invokeSetterMethod(Object obj, String propertyName, Object value) {
        invokeSetterMethod(obj, propertyName, value, (Class)null);
    }

    public static void invokeSetterMethod(Object obj, String propertyName, Object value, Class<?> propertyType) {
        Class<?> type = propertyType != null ? propertyType : value.getClass();
        String setterMethodName = "set" + StringUtils.capitalize(propertyName);
        invokeMethod(obj, setterMethodName, new Class[]{type}, new Object[]{value});
    }

    public static Object getFieldValue(Object obj, String fieldName) {
        Field field = getAccessibleField(obj, fieldName);
        Object result = null;
        if (field == null) {
            return result;
        } else {
            try {
                result = field.get(obj);
            } catch (IllegalAccessException var5) {
                logger.error("不可能抛出的异常{}", var5.getMessage());
            }

            return result;
        }
    }

    public static void setFieldValue(Object obj, String fieldName, Object value) {
        Field field = getAccessibleField(obj, fieldName);
        if (field == null) {
            throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
        } else {
            try {
                field.set(obj, value);
            } catch (IllegalAccessException var5) {
                logger.error("不可能抛出的异常:{}", var5.getMessage());
            }

        }
    }

    public static Field getAccessibleField(Object obj, String fieldName) {
        if (obj == null) {
            logger.error("ReflectionUtil.getAccessibleField(final Object obj, final String property)的obj参数不能为空");
            throw new NullPointerException("object不能为空");
        } else if (StringUtils.isBlank(fieldName)) {
            logger.error("ReflectionUtil.getAccessibleField(final Object obj, final String property)的fieldName参数不能为空");
            throw new NullPointerException("fieldName不能为空");
        } else {
            Class superClass = obj.getClass();

            while(superClass != Object.class) {
                try {
                    Field field = superClass.getDeclaredField(fieldName);
                    field.setAccessible(true);
                    return field;
                } catch (NoSuchFieldException var4) {
                    logger.error("NoSuchFieldException!");
                    superClass = superClass.getSuperclass();
                }
            }

            return null;
        }
    }

    public static Object invokeMethod(Object obj, String methodName, Class<?>[] parameterTypes, Object[] args) {
        Method method = getAccessibleMethod(obj, methodName, parameterTypes);
        if (method == null) {
            throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
        } else {
            try {
                return method.invoke(obj, args);
            } catch (Exception var6) {
                throw convertReflectionExceptionToUnchecked(var6);
            }
        }
    }

    public static Method getAccessibleMethod(Object obj, String methodName, Class<?>... parameterTypes) {
        if (obj == null) {
            logger.error("ReflectionUtil.getAccessibleField(final Object obj, final String property)的obj参数不能为空");
            throw new NullPointerException("object不能为空");
        } else {
            Class superClass = obj.getClass();

            while(superClass != Object.class) {
                try {
                    Method method = superClass.getDeclaredMethod(methodName, parameterTypes);
                    method.setAccessible(true);
                    return method;
                } catch (NoSuchMethodException var5) {
                    logger.error("NoSuchMethodException!", var5);
                    superClass = superClass.getSuperclass();
                }
            }

            return null;
        }
    }

    public static <T> Class<T> getSuperClassGenricType(Class clazz) {
        return getSuperClassGenricType(clazz, 0);
    }

    public static Class getSuperClassGenricType(Class clazz, int index) {
        Type genType = clazz.getGenericSuperclass();
        if (!(genType instanceof ParameterizedType)) {
            logger.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
            return Object.class;
        } else {
            Type[] params = ((ParameterizedType)genType).getActualTypeArguments();
            if (index < params.length && index >= 0) {
                if (!(params[index] instanceof Class)) {
                    logger.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
                    return Object.class;
                } else {
                    return (Class)params[index];
                }
            } else {
                logger.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " + params.length);
                return Object.class;
            }
        }
    }

    public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) {
        if (!(e instanceof IllegalAccessException) && !(e instanceof IllegalArgumentException) && !(e instanceof NoSuchMethodException)) {
            if (e instanceof InvocationTargetException) {
                return new RuntimeException("Reflection Exception.", ((InvocationTargetException)e).getTargetException());
            } else {
                return e instanceof RuntimeException ? (RuntimeException)e : new RuntimeException("Unexpected Checked Exception.", e);
            }
        } else {
            return new IllegalArgumentException("Reflection Exception.", e);
        }
    }

    public static Map<String, Object> getStaticField(Class clazz) throws Exception {
        Map<String, Object> fieldMap = Maps.newHashMap();
        Field[] fields = clazz.getDeclaredFields();
        if (fields != null && fields.length > 0) {
            Field[] var3 = fields;
            int var4 = fields.length;

            for(int var5 = 0; var5 < var4; ++var5) {
                Field field = var3[var5];
                field.setAccessible(true);
                if (Modifier.isStatic(field.getModifiers())) {
                    fieldMap.put(field.getName(), field.get(clazz));
                }
            }

            return fieldMap;
        } else {
            return fieldMap;
        }
    }

    public static Object getStaticField(Class clazz, String staticFieldName) {
        Object obj = null;
        Field[] fields = clazz.getDeclaredFields();
        if (fields != null && fields.length > 0) {
            try {
                Field[] var4 = fields;
                int var5 = fields.length;

                for(int var6 = 0; var6 < var5; ++var6) {
                    Field field = var4[var6];
                    field.setAccessible(true);
                    String fieldName = field.getName();
                    if (Modifier.isStatic(field.getModifiers()) && fieldName.equals(staticFieldName)) {
                        obj = field.get(clazz);
                    }
                }
            } catch (Exception var9) {
                obj = null;
            }

            return obj;
        } else {
            return obj;
        }
    }
}
